﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SmartRoute.Data;

namespace SmartRoute.Analytics
{
    //this class is responsible for taking solutions and testing their fitness
    public class FitnessTest
    {
        //both passenger limits and time limits form a 
        private int passengerLimit;
        private TimeSpan timeLimit;
        //used so to invert the scores so that high scores represent good solutions rather than the other way around
        private int inversionConstant;


        //CONSTRUCTOR, takes some fitness parameters
        public FitnessTest(int passengerLimit, TimeSpan timeLimit)
        {
            this.passengerLimit = passengerLimit;
            this.timeLimit = timeLimit;
            this.inversionConstant = 100000;
        }

        //takes a solution to test and returns a fitness score
        public double testFitness(BusSolution toTest)
        {
            //fitness score
            double fitnessScore = 0;

            //accumulators for total time
            double totalTime = 0;
            
            //keeps track of the time students are on the bus for each bus
            TimeSpan[] timeStudentsOn = new TimeSpan[toTest.Routes.Count];
            //keeps track of numbers of passengers over for each bus
            int[] passengersOver = new int[toTest.Passengers.Count];

            //number of violations
            int passengerViolations = 0;
            int timeViolations = 0;

            //calculates time students are on all buses
            //checks for time violation
            for (int i = 0; i < toTest.Routes.Count; i++ )
            {
                timeStudentsOn[i] = toTest.Routes[i].Duration - toTest.FirstLegWithoutPassengersDistance[i];
                if (timeStudentsOn[i] > timeLimit)
                {
                    timeViolations++;
                }
                totalTime += toTest.Routes[i].Duration.TotalSeconds;
            }

            //checks for passengerOverflow
            for (int i = 0; i < toTest.Passengers.Count; i++)
            {
                passengersOver[i] = toTest.Passengers[i] - passengerLimit;
                if (passengersOver[i] > 0)
                {
                    passengerViolations++;
                }
            }

            //inverts the fitness score
            fitnessScore =  this.inversionConstant / totalTime;

            //if any bus violates time constraints sets the fitness score to real low
            //can be replaced by a penalty rather than death
            if (timeViolations > 0)
            {
                fitnessScore = 1;
            }

            //if any bus violates passenger constraints sets the fitness score to real
            //low, can be replaced by a penalty rather than deat
            if (passengerViolations > 0)
            {
                fitnessScore = 1;
            }

            //no negative fitness scores
            if (fitnessScore <= 0)
            {
                fitnessScore = 1;
            }


            return fitnessScore;
        }

    }

    
}
